package com.aidex.system.service.impl;

import com.aidex.common.constant.Constants;
import com.aidex.common.constant.UserConstants;
import com.aidex.common.core.domain.TreeNode;
import com.aidex.common.core.domain.TreeSelect;
import com.aidex.common.core.domain.entity.SysMenu;
import com.aidex.common.core.domain.entity.SysRole;
import com.aidex.common.core.domain.entity.SysUser;
import com.aidex.common.core.service.impl.BasicTreeServiceImpl;
import com.aidex.common.exception.BizException;
import com.aidex.common.utils.NumberUtils;
import com.aidex.common.utils.StringUtils;
import com.aidex.common.utils.uuid.IdUtils;
import com.aidex.system.common.SysErrorCode;
import com.aidex.system.domain.SysRoleMenu;
import com.aidex.system.domain.vo.MetaVo;
import com.aidex.system.domain.vo.RouterVo;
import com.aidex.system.mapper.SysMenuMapper;
import com.aidex.system.mapper.SysRoleMenuMapper;
import com.aidex.system.service.SysMenuService;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl extends BasicTreeServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Autowired
    private SysRoleMenuMapper roleMenuMapper;

    @Override
    public int insert(SysMenu menu) {
        checkMenuNameUnique(menu);
        checkMenuCodeUnique(menu);
        SysMenu parentSysMenu = mapper.selectById(menu.getParentId());
        int flag;
        if (StringUtils.isEmpty(menu.getId())) {
            if (null != parentSysMenu) {
                // 如果父节点不为正常状态,则不允许新增子节点
                if (!UserConstants.DEPT_NORMAL.equals(parentSysMenu.getStatus())) {
                    throw new BizException(SysErrorCode.B_SYSMENU_MenuAlreadyUnNormal, "菜单停用，不允许新增子菜单");
                }
                setTreeProperties(menu, null, Constants.OpType.insert);
                flag = super.insert(menu);
            } else {
                //新增根节点
                menu.setId(IdUtils.randomUUID());
                menu.setParentIds(menu.getId());
                // 设置当前树全路径排序
                Integer treeSort = menu.getTreeSort();
                String treeSorts = String.format("%06d", treeSort);
                menu.setTreeSorts(treeSorts);
                menu.setTreeLeaf(Constants.TREE_LEAF_Y);
                // 设置当前节点级别.
                menu.setTreeLevel(1);
                flag = super.insert(menu);
            }
        } else {
            //编辑
            SysMenu oldSysMenu = mapper.selectById(menu);
            if (isMoveToSelfChildNode(menu, oldSysMenu)) {
                throw new BizException(SysErrorCode.B_SYSMENU_MenuMoveUnNormal, "非法移动，不允许将节点移动到自身或者子节点下");
            }
            List<SysMenu> updateChildList = new ArrayList<SysMenu>();
            if (menu.getParentId().equals(menu.getId())) {
                throw new BizException(SysErrorCode.B_SYSMENU_MenuIdNotEqualParentId, "修改菜单失败，父级菜单不能是自己");
            }
            QueryWrapper<SysMenu> wrapper = new QueryWrapper<>();
            wrapper.eq("del_flag", "0");
            wrapper.like("parent_ids", menu.getParentIds());
            wrapper.ne("parent_ids", menu.getParentIds());
            if (StringUtils.equals(UserConstants.DEPT_DISABLE, menu.getStatus()) && mapper.selectCount(wrapper) > 0) {
                throw new BizException(SysErrorCode.B_SYSMENU_MenuHasNormalChild, "该菜单包含未停用的子菜单，不允许标记为停用");
            }
            if (isUpdateTreeProperties(menu, oldSysMenu)) {
                setTreeProperties(menu, oldSysMenu, Constants.OpType.update);
                updateChildList = updateChildTreeProperties(menu, oldSysMenu);
                if (!CollectionUtils.isEmpty(updateChildList)) {
                    for (SysMenu child : updateChildList) {
                        mapper.updateById(child);
                    }
                }
            }
            parentSysMenu = mapper.selectById(menu.getParentId());
            // 新的父节点变更为非叶子节点
            if (!Constants.TREE_ROOT.equals(menu.getParentId()) && parentSysMenu.getTreeLeaf().equals(Constants.TREE_LEAF_Y)) {
                parentSysMenu.setTreeLeaf(Constants.TREE_LEAF_N);
                flag = super.updateById(parentSysMenu);
            }
            String oldParentId = oldSysMenu.getParentId();
            flag = super.updateById(menu);
            // 判断原节点是否还有子节点，否则改为叶子节点
            if (!hasChildByDeptId(oldParentId)) {
                SysMenu oldParentSysMenu = mapper.selectById(oldParentId);
                oldParentSysMenu.setTreeLeaf(Constants.TREE_LEAF_Y);
                flag = super.updateById(oldParentSysMenu);
            }
        }

        return flag;
    }

    @Override
    public boolean hasChildByDeptId(String menuId) {
        int result = findChildCountById(menuId);
        return result > 0 ? true : false;
    }

    public Integer findChildCountById(String parentId) {
        QueryWrapper<SysMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id", parentId);
        return mapper.selectCount(wrapper);
    }

    @Override
    public Set<String> selectMenuPermsByUserId(String userId) {
        List<SysMenu> menus = selectList(new QueryWrapper());
        Set<String> perms = new HashSet<>();
        for (SysMenu menu : menus) {
            if (StringUtils.isNotEmpty(menu.getPerms())) {
                perms.addAll(Arrays.asList(menu.getPerms().split(",")));
            }
        }
        return perms;
    }

    @Override
    public List<String> selectMenuIdsByRoleId(String roleId) {
        QueryWrapper<SysRoleMenu> wrapper = new QueryWrapper<>();
        wrapper.select("menu_id").eq("role_id", roleId);
        List<SysRoleMenu> roleMenus = roleMenuMapper.selectList(wrapper);
        List<String> menuIds = new ArrayList<>();
        if (roleMenus != null) {
            for (SysRoleMenu roleMenu : roleMenus) {
                menuIds.add(roleMenu.getMenuId());
            }
        }
        return menuIds;
    }

    @Override
    public List<RouterVo> buildMenus(List<SysMenu> menus) {
        List<RouterVo> routers = null;
        if(menus != null && !menus.isEmpty()) {
            routers = new LinkedList<>();
            for (SysMenu menu : menus) {
                if("1".equals(menu.getDelFlag())) {
                    continue;
                }
                RouterVo router = new RouterVo();
                router.setHidden("1".equals(menu.getVisible()));
                router.setName(getRouteName(menu));
                router.setPath(getRouterPath(menu));
                router.setComponent(getComponent(menu));
                router.setIsFrame(menu.getIsFrame());
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getRemark()));
                List<SysMenu> cMenus = menu.getChildren();
                if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
                    router.setAlwaysShow(true);
                    router.setRedirect("noRedirect");
                    router.setChildren(buildMenus(cMenus));
                } else if (isMeunFrame(menu)) {
                    List<RouterVo> childrenList = new ArrayList<>();
                    RouterVo children = new RouterVo();
                    children.setPath(menu.getPath());
                    children.setComponent(menu.getComponent());
                    children.setName(StringUtils.capitalize(menu.getPath()));
                    children.setIsFrame(menu.getIsFrame());
                    children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getRemark()));
                    childrenList.add(children);
                    router.setChildren(childrenList);
                }
                routers.add(router);
            }
        }
        return routers;
    }

    @Override
    public List<SysMenu> selectList(QueryWrapper<SysMenu> wrapper, String userId) {
        wrapper.eq("parent_id", "0");
        wrapper.eq("del_flag", "0");
        return mapper.selectList(wrapper);
    }

    @Override
    public boolean hasChildByMenuId(String parentId) {
        QueryWrapper<SysMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id", parentId);
        return mapper.selectCount(wrapper) > 0;
    }

    @Override
    public boolean checkMenuExistRole(String menuId) {
        QueryWrapper<SysRoleMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("menu_id", menuId);
        return roleMenuMapper.selectCount(wrapper) > 0;
    }

    @Override
    public void checkMenuNameUnique(SysMenu menu) {
        QueryWrapper<SysMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("menu_name", menu.getMenuName());
        wrapper.eq("parent_id", menu.getParentId());
        wrapper.ne("id", menu.getId());
        if (mapper.selectCount(wrapper) > 0) {
            throw new BizException(SysErrorCode.B_SYSMENU_MenuNameAlreadyExist);
        }
    }

    @Override
    public void checkMenuCodeUnique(SysMenu menu) {
        QueryWrapper<SysMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("menu_code", menu.getMenuCode());
        wrapper.ne("id", menu.getId());
        if (mapper.selectCount(wrapper) > 0) {
            throw new BizException(SysErrorCode.B_SYSMENU_PathAlreadyExist);
        }
    }

    public String getRouteName(SysMenu menu) {
        String routerName = StringUtils.capitalize(menu.getPath());
        // 非外链并且是一级目录（类型为目录）
        if (isMeunFrame(menu)) {
            routerName = StringUtils.EMPTY;
        }
        return routerName;
    }

    public String getRouterPath(SysMenu menu) {
        String routerPath = menu.getPath();
        // 非外链并且是一级目录（类型为目录）
        if ("0".equals(menu.getParentId()) && UserConstants.TYPE_DIR.equals(menu.getMenuType())
                && UserConstants.NO_FRAME.equals(menu.getIsFrame())) {
            routerPath = "/" + menu.getPath();
        }
        // 非外链并且是一级目录（类型为菜单）
        else if (isMeunFrame(menu)) {
            routerPath = "/";
        }
        return routerPath;
    }

    public String getComponent(SysMenu menu) {
        String component = UserConstants.LAYOUT;
        if (StringUtils.isNotEmpty(menu.getComponent()) && !isMeunFrame(menu)) {
            component = menu.getComponent();
        } else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu)) {
            component = UserConstants.PARENT_VIEW;
        }
        return component;
    }

    public boolean isMeunFrame(SysMenu menu) {
        return "0".equals(menu.getParentId()) && UserConstants.TYPE_MENU.equals(menu.getMenuType()) && menu.getIsFrame().equals(UserConstants.NO_FRAME);
    }

    public boolean isParentView(SysMenu menu) {
        return !"0".equals(menu.getParentId()) && UserConstants.TYPE_DIR.equals(menu.getMenuType());
    }

    @Override
    public int deleteById(Serializable id) {
        SysMenu menu = mapper.selectById(id);
        if (hasChildByDeptId(menu.getId())) {
            throw new BizException(SysErrorCode.B_SYSMENU_MenuHasChildNotDelete, "该菜单包含子菜单，不允许删除");
        }
        int flag = super.deleteById(id);
        // 判断当前父节点下还是否有子节点，如果没有，则需要把父节点置为叶子节点
        SysMenu parentSysMenu = mapper.selectById(menu.getParentId());
        if (findChildCountById(menu.getParentId()) == 0) {
            parentSysMenu.setTreeLeaf(Constants.TREE_LEAF_Y);
            super.updateById(parentSysMenu);
        }
        return flag;
    }

    @Override
    public List<TreeNode> buildMenusTree(List<SysMenu> menus) {
        List<TreeNode> listData = new ArrayList<>();
        for (SysMenu menu : menus) {
            TreeNode treeNode = this.transToTreeNodeData(menu);
            if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
                treeNode.setChildren(this.buildMenusTree(menu.getChildren()));
            } else {
                treeNode.setChildren(null);
            }
            //不展开节点的父节点数据处理
            if (CollectionUtils.isEmpty(treeNode.getChildren())) {
                treeNode.setChildren(null);
            }
            listData.add(treeNode);
        }
        return listData;
    }

    private TreeNode transToTreeNodeData(SysMenu menu) {
        TreeNode treeNode = new TreeNode();
        treeNode.setId(menu.getId());
        treeNode.setKey(menu.getId());
        treeNode.setTitle(menu.getMenuName());
        treeNode.setLabel(menu.getMenuName());
        treeNode.setSelectable(true);
        treeNode.setDisabled(false);
        treeNode.setDisableCheckbox(false);
        treeNode.setParentId(menu.getParentId());
        treeNode.setParentIds(menu.getParentIds());
        HashMap<String, Object> attr = new HashMap<>(3);
        attr.put("treeLeaf", menu.getTreeLeaf());
        attr.put("treeLevel", menu.getTreeLevel());
        attr.put("treePath", menu.getParentIds());
        treeNode.setAttributes(attr);
        if (Constants.TREE_LEAF_Y.equals(menu.getTreeLeaf())) {
            treeNode.setIsLeaf(true);
        } else {
            treeNode.setIsLeaf(false);
        }
        JSONObject slotsValue = new JSONObject();
        JSONObject scopedSlotsValue = new JSONObject();
        treeNode.setSlots(slotsValue);
        treeNode.setScopedSlots(scopedSlotsValue);
        return treeNode;
    }

    @Override
    public Integer findMaxSort(SysMenu menu) {
        return NumberUtils.nextOrder(mapper.findMaxSort(menu.getParentId()));
    }
}
